/*
 * coveringPacking.cpp
 *
 *  Created on: May 14, 2013
 *      Author: sjelic
 */

#include "Gurobi.h"
#include "parallelYoung.h"
#include "solver.h"

double get_time();
int main()
{
	int method,mode;
	Miscellaneous::experimentUsage();
	std::cout<<"Choose method (1, 2, 3 or 4): ";
	std::cin>>method;
	std::cout<<std::endl;
	std::cout<<std::endl;
	std::cout<<"Choose mode (1 or 2): ";
	std::cin>>mode;
	std::cout<<std::endl;
	std::cout<<std::endl;

	if(method==1)
	{
		std::cout<<"----------------GUROBI optimizer------------------------------"<<std::endl;
		std::cout<<std::endl;
		std::cout<<std::endl;
		if(mode==1)
		{
			string path;
			string logFile;
			double EPS;
			double D;
			bool normalized;
			std::cout<<"----------------Experiment on single instance-----------------"<<std::endl;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Type in instance path: ";
			std::cin>>path;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Type in precision eps : ";
			std::cin>>EPS;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Type in log-file path: ";
			std::cin>>logFile;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Problem normalized (1 if YES, 0 if NO)?: ";
			std::cin>>normalized;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::string match("-");
			D = (double)atof(path.substr(path.find(match)+1,3).c_str());
			coveringPacking::GurobiLP myGurobi = coveringPacking::GurobiLP(D,EPS,logFile,normalized);
			myGurobi.convertMatrixAFromYoungToGurobiModel(path);
			if(GRBsetcallbackfunc(myGurobi.myModel, coveringPacking::mycallback, (void *) &myGurobi.myTestData)) std::cout<<"Problem with setting up callback function"<<std::endl;
			myGurobi.tuningAndSolvingModel();
			//GRBfreemodel(myGurobi.myModel);
			//myGurobi.~GurobiLP();

		}
		else if(mode==2)
		{
			string path,pathResults,logFile;
			int numberOfEps;
			std::cout<<"----------------Experiment on multiple instances--------------"<<std::endl;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Type in directory path: ";
			std::cin>>path;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Type in path to the result file: ";
			std::cin>>pathResults;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Type in number of eps : ";
			std::cin>>numberOfEps;
			//std::cout<<"Number of Eps: "<<numberOfEps<<std::endl;
			std::cout<<std::endl;
			std::cout<<std::endl;
			double* EPS = new double[numberOfEps];


			std::cout<<"1.eps : ";
			std::cin>>EPS[0];
			std::cout<<std::endl;
			std::cout<<"2.eps : ";
			std::cin>>EPS[1];
			std::cout<<std::endl;
			std::cout<<"3.eps : ";
			std::cin>>EPS[2];
			std::cout<<std::endl;

			/*for(int i=0; i++; i<numberOfEps)
			{
				//std::cout<<"      "<<(i+1)<<". eps:";
				std::cin>>EPS[i];
				//std::cout<<std::endl;
			}*/
			std::cout<<"Type in log-file path: ";
			std::cin>>logFile;
			std::cout<<std::endl;
			std::cout<<std::endl;
			DIR *dpdf;
			double D;
			bool normalized = true;
			struct dirent *epdf;
			char* filename;
			std::string match("-");

			dpdf = opendir(path.c_str());
			if (dpdf != NULL){
				epdf = readdir(dpdf);
				while (epdf){

					filename=epdf->d_name;
					if(!!strncmp(filename,"..",2)&&!!strncmp(filename,".",1))
					{
						std::string name (filename);
						string pathData=path+name;
						D = (double)atof(name.substr(name.find(match)+1,3).c_str());
						//D=0.33;
						for(int i=0; i<numberOfEps; i++)
						{
							coveringPacking::GurobiLP myGurobi = coveringPacking::GurobiLP(D,EPS[i],logFile,normalized);
							myGurobi.convertMatrixAFromYoungToGurobiModel(pathData);
							if(GRBsetcallbackfunc(myGurobi.myModel, coveringPacking::mycallback, (void *) &myGurobi.myTestData)) std::cout<<"Problem with setting up callback function"<<std::endl;
							myGurobi.tuningAndSolvingModel();
							myGurobi.writingResultsToFile(pathResults,'&');
							//myGurobi.~GurobiLP();
						}
					}
					epdf = readdir(dpdf);
			   }
			}
			delete []EPS;
		}
		else
		{
			std::cout<<"You didn't type 1 or 2!!!"<<std::endl;
			Miscellaneous::experimentUsage();
		}

	}
	else if(method==2)
	{
		std::cout<<"----------------Parallel Derandomized Young Solver-------------------"<<std::endl;
		std::cout<<std::endl;
		std::cout<<std::endl;
		if(mode==1)
		{
			string path,logFile;
			bool normalized;
			float D;
			real EPS,EPSPrime,BETA;
			//real beta;
			std::cout<<"----------------Experiment on single instance-----------------"<<std::endl;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Type in instance path: ";
			std::cin>>path;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Type in precision eps : ";
			std::cin>>EPS;
			std::cout<<std::endl;
			std::cout<<std::endl;

			std::cout<<"Type in BETA : ";
			std::cin>>EPSPrime;
			std::cout<<std::endl;
			std::cout<<std::endl;

			/*std::cout<<"Type in BETA : ";
			std::cin>>BETA;
			std::cout<<std::endl;
			std::cout<<std::endl;*/

			std::cout<<"Problem normalized (1 if YES, 0 if NO)?: ";
			std::cin>>normalized;
			std::cout<<std::endl;
			std::cout<<std::endl;

			/*std::cout<<"Type in log-file path: ";
			std::cin>>logFile;
			std::cout<<std::endl;
			std::cout<<std::endl;*/
			std::string match("-");
			D = (float)atof(path.substr(path.find(match)+1,3).c_str());


			coveringPacking::ParallelYoungDerandomized myParallelYoungDerandomized = coveringPacking::ParallelYoungDerandomized(EPS,path,D,normalized);

			//BETA = EPSPrime;
			BETA=3*log(myParallelYoungDerandomized.myPackingLinearProgram->numberOfNonzero);
			//BETA=500;
			myParallelYoungDerandomized.optimizeInstance(0,BETA);
			myParallelYoungDerandomized.cpuScalingSolutions();


		}
		else if(mode==2)
		{
			string path,pathResults;
			bool normalized;
			int numberOfEps;
			real BETA;
			std::cout<<"----------------Experiment on multiple instances--------------"<<std::endl;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Type in directory path: ";
			std::cin>>path;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Type in path to the result file: ";
			std::cin>>pathResults;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Type in number of eps : ";
			std::cin>>numberOfEps;
			std::cout<<std::endl;
			std::cout<<std::endl;
			/*std::cout<<"Type in BETA : ";
			std::cin>>BETA;
			std::cout<<std::endl;
			std::cout<<std::endl;*/
			real* EPS = new real[numberOfEps];


			std::cout<<"1.eps : ";
			std::cin>>EPS[0];
			std::cout<<std::endl;
			std::cout<<"2.eps : ";
			std::cin>>EPS[1];
			std::cout<<std::endl;
			std::cout<<"3.eps : ";
			std::cin>>EPS[2];
			std::cout<<std::endl;
			std::cout<<"Problems normalized (1 if YES, 0 if NO)?: ";
			std::cin>>normalized;
			std::cout<<std::endl;
			std::cout<<std::endl;

			/*for(int i=0; i++; i<numberOfEps)
			{
				//std::cout<<"      "<<(i+1)<<". eps:";
				std::cin>>EPS[i];
				//std::cout<<std::endl;
			}*/

			DIR *dpdf;
			double D;
			struct dirent *epdf;
			char* filename;
			std::string match("-");
			dpdf = opendir(path.c_str());
			if (dpdf != NULL){
				epdf = readdir(dpdf);
				while (epdf){
					filename=epdf->d_name;
					if(!!strncmp(filename,"..",2)&&!!strncmp(filename,".",1))
					{
						std::string name (filename);
						string pathData=path+name;
						D = (double)atof(name.substr(name.find(match)+1,3).c_str());
						for(int i=0; i<numberOfEps; i++)
						{
							for(int jj=10; jj<20; jj=jj+10)
							{
							coveringPacking::ParallelYoungDerandomized myParallelYoungDerandomized = coveringPacking::ParallelYoungDerandomized(EPS[i],pathData,D,normalized);
							BETA=3*log(myParallelYoungDerandomized.myPackingLinearProgram->numberOfNonzero);
							myParallelYoungDerandomized.optimizeInstance(0,BETA);
							//float time=myParallelYoungDerandomized.myPerformanceStructures->totalComputationTime();
							myParallelYoungDerandomized.writingResultsToFileOnlyTimes(pathResults,"newLine",0,0,'&');
							//myParallelYoungDerandomized.optimizeInstance(0.5,BETA);
							myParallelYoungDerandomized.cpuScalingSolutions();
							myParallelYoungDerandomized.writingResultsToFileOnlyTimes(pathResults,"endLine",myParallelYoungDerandomized.myPerformanceStructures->getPrimalDualGap(),BETA,'&');

							}
						}
					}
					epdf = readdir(dpdf);
			   }
			}
			else
			{
				std::cout<<"Directory doesn't exist!!!"<<std::endl;
			}
			delete []EPS;
		}
	}
	else if(method==4)
	{
		std::cout<<"----------------Sequential Randomized Young Solver-------------------"<<std::endl;
		std::cout<<std::endl;
		std::cout<<std::endl;
		if(mode==1)
		{
			string path,logFile;
			bool normalized;
			real EPS;
			//real beta;
			std::cout<<"----------------Experiment on single instance-----------------"<<std::endl;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Type in instance path: ";
			std::cin>>path;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Type in precision eps : ";
			std::cin>>EPS;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Problem normalized (1 if YES, 0 if NO)?: ";
			std::cin>>normalized;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::string match("-");
			float D = (float)atof(path.substr(path.find(match)+1,3).c_str());
			Solver* s = Solver::create(EPS,D);

			std::ifstream in_file(path.c_str());

			if (in_file.fail()) {
				std::cerr << "Error opening " << path << std::endl;
				return -1;
			}

			//std::stringstream in_file;
			//in_file << in_file0.rdbuf();

			std::cout << "INPUT FILE: " << path << std::endl;

			//read and parse 1st line of input (parameters)
			int R, C, r, c, total;
			double val;
			char buffer[1024];

			in_file >> R >> C >> total;

			int non_zero_entry_count = 0;
			double			main_start_time = get_time();
			int i=0;
			while(i<total) {
				char* p = buffer;

				in_file.getline(p, 1024);

				if (in_file.eof()) break;

				if(non_zero_entry_count == total) {
					std::cout << "warning: input file claimed " << total << " non-zeros, but there are more (ignoring)" << std::endl;
					break;
				}
				// below is about 6-10 times faster than "in_file >> r >> c >> val;"
				r = int(strtol(p, &p, 10));
				c = int(strtol(p, &p, 10));
				val = strtod(p, &p);

				assert(0 <= r && r < R && 0 <= c && c < C);
				if (val == 0)			continue;
				s->add_entry(r, c, abs(val));
				++non_zero_entry_count;
				++i;
			}

			std::cout << "preprocessing_time0 = " << get_time() - main_start_time << " s" << std::endl;

			s->done_adding_entries();

			std::cout << "preprocessing_time1 = " << get_time() - main_start_time << " s" << std::endl;
			//std::cout<<" non_zero_entry_count <-> total "<<non_zero_entry_count<<" <->"<<total<<std::endl;
			assert(R == s->n_rows()  &&  C == s->n_cols()  &&  non_zero_entry_count == total);


			std::cout << "ROWS: " <<  s->n_rows() << " COLUMNS: " << s->n_cols() << " NON-ZEROS: " << total
				<< " DENSITY: " << (double)total/((double)s->n_rows()*(double)s->n_cols())<< std::endl;

			std::cout << "preprocessing_time = " << get_time() - main_start_time << " s" << std::endl;

			srand(time(0));


			if(s->solve()) {
				std::cout << "solved" << std::endl;
			} else {
				std::cout << "not solved" << std::endl;
			}
			double col_value = 0, row_value = 0;

			for (int row = 0;  row < s->n_rows();  ++row)  row_value += s->value_of_row_variable(row);
			for (int col = 0;  col < s->n_cols();  ++col)  col_value += s->value_of_col_variable(col);




		}
		else if(mode==2)
		{
			string path,pathResults;
			bool normalized;
			int numberOfEps;
			std::cout<<"----------------Experiment on multiple instances--------------"<<std::endl;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Type in directory path: ";
			std::cin>>path;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Type in path to the result file: ";
			std::cin>>pathResults;
			std::cout<<std::endl;
			std::cout<<std::endl;
			std::cout<<"Type in number of eps : ";
			std::cin>>numberOfEps;
			//std::cout<<"Number of Eps: "<<numberOfEps<<std::endl;
			std::cout<<std::endl;
			std::cout<<std::endl;
			real* EPS = new real[numberOfEps];


			std::cout<<"1.eps : ";
			std::cin>>EPS[0];
			std::cout<<std::endl;
			std::cout<<"2.eps : ";
			std::cin>>EPS[1];
			std::cout<<std::endl;
			std::cout<<"3.eps : ";
			std::cin>>EPS[2];
			std::cout<<std::endl;
			std::cout<<"Problems normalized (1 if YES, 0 if NO)?: ";
			std::cin>>normalized;
			std::cout<<std::endl;
			std::cout<<std::endl;

			/*for(int i=0; i++; i<numberOfEps)
			{
				//std::cout<<"      "<<(i+1)<<". eps:";
				std::cin>>EPS[i];
				//std::cout<<std::endl;
			}*/

			DIR *dpdf;
			double D;
			struct dirent *epdf;
			char* filename;
			std::string match("-");
			dpdf = opendir(path.c_str());
			if (dpdf != NULL){
				epdf = readdir(dpdf);
				while (epdf){
					filename=epdf->d_name;
					if(!!strncmp(filename,"..",2)&&!!strncmp(filename,".",1))
					{
						std::string name (filename);
						string pathData=path+name;
						D = (double)atof(name.substr(name.find(match)+1,3).c_str());
						for(int i=0; i<numberOfEps; i++)
						{
							Solver* s = Solver::create(EPS[i],D);

							std::ifstream in_file(pathData.c_str());

							if (in_file.fail()) {
								std::cerr << "Error opening " << path << std::endl;
								return -1;
							}

							//std::stringstream in_file;
							//in_file << in_file0.rdbuf();

							std::cout << "INPUT FILE: " << pathData << std::endl;

							//read and parse 1st line of input (parameters)
							int R, C, r, c, total;
							double val;
							char buffer[1024];

							in_file >> R >> C >> total;

							int non_zero_entry_count = 0;
							double			main_start_time = get_time();
							int i=0;
							while(i++<total) {
								char* p = buffer;

								in_file.getline(p, 1024);

								if (in_file.eof()) break;

								if(non_zero_entry_count == total) {
									std::cout << "warning: input file claimed " << total << " non-zeros, but there are more (ignoring)" << std::endl;
									break;
								}
								// below is about 6-10 times faster than "in_file >> r >> c >> val;"
								r = int(strtol(p, &p, 10));
								c = int(strtol(p, &p, 10));
								val = strtod(p, &p);

								assert(0 <= r && r < R && 0 <= c && c < C);
								if (val == 0)			continue;
								s->add_entry(r, c, abs(val));
								++non_zero_entry_count;
							}

							std::cout << "preprocessing_time0 = " << get_time() - main_start_time << " s" << std::endl;

							s->done_adding_entries();

							std::cout << "preprocessing_time1 = " << get_time() - main_start_time << " s" << std::endl;

							assert(R == s->n_rows()  &&  C == s->n_cols()  &&  non_zero_entry_count == total);

							std::cout << "ROWS: " <<  s->n_rows() << " COLUMNS: " << s->n_cols() << " NON-ZEROS: " << total
								<< " DENSITY: " << (double)total/((double)s->n_rows()*(double)s->n_cols())<< std::endl;

							std::cout << "preprocessing_time = " << get_time() - main_start_time << " s" << std::endl;

							srand(time(0));


							if(s->solve()) {
								std::cout << "solved" << std::endl;
							} else {
								std::cout << "not solved" << std::endl;
							}
							double col_value = 0, row_value = 0;

							for (int row = 0;  row < s->n_rows();  ++row)  row_value += s->value_of_row_variable(row);
							for (int col = 0;  col < s->n_cols();  ++col)  col_value += s->value_of_col_variable(col);

							s->writingResultsToFile(pathResults,'&');
						}
					}
					epdf = readdir(dpdf);
			   }
			}
			else
			{
				std::cout<<"Directory doesn't exist!!!"<<std::endl;
			}
			delete []EPS;
		}
		else
		{
			std::cout<<"You didn't type 1 or 2!!!"<<std::endl;
			Miscellaneous::experimentUsage();
		}
	}
	else if(method==5)
	{
		string railPath, youngPath;
		std::cout<<"----------------Convert Rail Instance to Young Sparse Format--------------"<<std::endl;
		std::cout<<std::endl;
		std::cout<<std::endl;
		std::cout<<"Type in path to the Rail covering instance: ";
		std::cin>>railPath;
		std::cout<<std::endl;
		std::cout<<std::endl;
		std::cout<<"Type in path to the Young Rail covering instance: ";
		std::cin>>youngPath;
		std::cout<<std::endl;
		std::cout<<std::endl;
		Miscellaneous::convertRailFormatToYoung(railPath,youngPath);


	}
	else
	{
		std::cout<<"You didn't type 1 or 2!!!"<<std::endl;
		Miscellaneous::experimentUsage();
	}




	return 0;

}




